//*******************************************************************
//
//  UNIT:     G r 3 2 _ P N G     15.Jan.2005,  4.August 2005
//
//  PNG Graphic Unit for graphics32 library v1.7.x and higher
//  to load and save PNG images (Portable Network Graphics)
//
//  needs TPNGImage component from Gustavo Daud (gustavodaud@uol.com.br)
//  http://pngdelphi.sourceforge.net/
//
//  FAQ:
//  Q: Is there a PNG library for GR32 which supports loading and saving
//     an image and its alpha channel at the same time?
//
//  A: Yes, you need TPNGImage component from Gustavo Daud
//     and this unit to load and save PNG images.
//
//  LoadPNGintoBitmap32 code taken from
//  http://graphics32.org/wiki/pub/page/FAQ/ImageFormatRelated
//
//  note: if you use standard picture file dialogs of type TOpenPictureDialog
//        or TSavePictureDialog to load or save PNG pictures, you have to add
//        string   "Portable Network Graphics (*.png)"   and   "*.png"
//        to filter property !
//
//  --- functions and procedures ---
//
//  LoadPNGintoBitmap32           load PNG image file into Bitmap32
//  SaveBitmap32ToPNG             save Bitmap32 to PNG image file
//
//  Bitmap32ToPNG                 convert Bitmap32 to PNG object
//
//*******************************************************************
unit Gr32_PNG;

INTERFACE

uses   SysUtils, Classes, Graphics, GR32, PNGImage;

function LoadPNGintoBitmap32 (destBitmap: TBitmap32; srcStream: TStream; out transparent: Boolean): boolean; overload;
function LoadPNGintoBitmap32 (destBitmap: TBitmap32; filename: String; out transparent: Boolean): boolean; overload;

function SaveBitmap32ToPNG (sourceBitmap: TBitmap32; transparent: Boolean; bgColor32: TColor32; filename: String; compressionLevel: TCompressionLevel = 9; interlaceMethod: TInterlaceMethod = imNone): boolean;
function Bitmap32ToPNG (sourceBitmap: TBitmap32; paletted, transparent: Boolean; bgColor: TColor; compressionLevel: TCompressionLevel = 9; interlaceMethod: TInterlaceMethod = imNone): tPNGObject;

IMPLEMENTATION

//*********************************************************
// load PNG image from source stream
// input:   destBitmap: TBitmap32;    destination bitmap
//          srcStream: TStream;       source stream
// output:  transparent: boolean;     =true: alpha channel used
// return:  boolean;                  =true: png image file loaded
//---------------------------------------------------------
function LoadPNGintoBitmap32 (destBitmap: TBitmap32;
                               srcStream: TStream;
                               out transparent: Boolean): boolean;
var
   PNGObject: TPNGObject;
   TransparentColor: TColor32;
   PixelPtr: PColor32;
   AlphaPtr: PByte;
   X, Y: Integer;
begin
   PNGObject := nil;
   try
     result := false;
     PNGObject := TPngObject.Create;
     PNGObject.LoadFromStream(srcStream);

     destBitmap.Assign(PNGObject);
     destBitmap.ResetAlpha;

     case PNGObject.TransparencyMode of
       ptmPartial: begin
           if (PNGObject.Header.ColorType = COLOR_GRAYSCALEALPHA) or
              (PNGObject.Header.ColorType = COLOR_RGBALPHA) then begin
             PixelPtr := PColor32(@destBitmap.Bits[0]);
             for Y := 0 to destBitmap.Height - 1 do begin
               AlphaPtr := PByte(PNGObject.AlphaScanline[Y]);
               for X := 0 to destBitmap.Width - 1 do begin
                 PixelPtr^ := (PixelPtr^ and $00FFFFFF) or (TColor32(AlphaPtr^) shl 24);
                 Inc(PixelPtr);
                 Inc(AlphaPtr);
               end; {for-X}
             end; {for-Y}
             transparent := True;
           end; {if}
         end; {case-ptmPartial}
       ptmBit:
         begin
           TransparentColor := Color32(PNGObject.TransparentColor);
           PixelPtr := PColor32(@destBitmap.Bits[0]);
           for X := 0 to (destBitmap.Height - 1) * (destBitmap.Width - 1) do
           begin
             if PixelPtr^ = TransparentColor then
               PixelPtr^ := PixelPtr^ and $00FFFFFF;
             Inc(PixelPtr);
           end;
           transparent := True;
         end;
       ptmNone:
         transparent := False;
     end;
     result := true;
   finally
     if Assigned(PNGObject) then PNGObject.Free;
   end;
end;
//*********************************************************
// load PNG image file into Bitmap32
// input:   destBitmap: TBitmap32;    destination bitmap
//          filename: String;         name of PNG image file
// output:  transparent: boolean;     =true: alpha channel used
// return:  boolean;                  =true: png image file loaded
//---------------------------------------------------------
function LoadPNGintoBitmap32 (destBitmap: TBitmap32;
                               filename: String;
                               out transparent: boolean): boolean;
var
   FileStream: TFileStream;
begin
   result := false;
   try
     FileStream := TFileStream.Create(filename, fmOpenRead);
     try
       result := LoadPNGintoBitmap32(destBitmap, FileStream, transparent);
     finally
       FileStream.Free;
     end;
   except
   end;
end;

//*********************************************************
// convert Bitmap32 to PNG image
// input:   sourceBitmap      source bitmap 32 bit
//          paletted          =true: PixelFormat is pf8bit
//          transparent       =true: transparent pixels
//          bgColor           background color
//          compressionLevel  compression level, range 0..9, default = 9
//          interlaceMethod   interlaced method, use imNone or imAdam7
// return:  tPNGObject        PNG image object
//---------------------------------------------------------
function Bitmap32ToPNG (sourceBitmap: TBitmap32;
                         paletted, transparent: Boolean;
                         bgColor: TColor;
                         compressionLevel: TCompressionLevel = 9;
                         interlaceMethod: TInterlaceMethod = imNone):
tPNGObject;
var
   bm: TBitmap;
   png: TPngObject;
   TRNS: TCHUNKtRNS;
   p: pngImage.PByteArray;
   x, y: Integer;
begin
   Result := nil;
   png := TPngObject.Create;
   try
     bm := TBitmap.Create;
     try
       bm.Assign (sourceBitmap);        // convert data into bitmap
       // force paletted on TBitmap, transparent for the web must be 8bit
       if paletted then
         bm.PixelFormat := pf8bit;
       png.interlaceMethod := interlaceMethod;
       png.compressionLevel := compressionLevel;
       png.Assign(bm);                  // convert bitmap into PNG
     finally
       FreeAndNil(bm);
     end;
     if transparent then begin
       if png.Header.ColorType in [COLOR_PALETTE] then begin
         if (png.Chunks.ItemFromClass(TChunktRNS) = nil) then png.CreateAlpha;
         TRNS := png.Chunks.ItemFromClass(TChunktRNS) as TChunktRNS;
         if Assigned(TRNS) then TRNS.TransparentColor := bgColor;
       end;
       if png.Header.ColorType in [COLOR_RGB, COLOR_GRAYSCALE] then png.CreateAlpha;
       if png.Header.ColorType in [COLOR_RGBALPHA, COLOR_GRAYSCALEALPHA] then
       begin
         for y := 0 to png.Header.Height - 1 do begin
           p := png.AlphaScanline[y];
           for x := 0 to png.Header.Width - 1
           do p[x] := AlphaComponent(sourceBitmap.Pixel[x,y]);  //TARGB(bm32.Pixel[x,y]).a;
         end;
       end;
     end;
     Result := png;
   except
     png.Free;
   end;
end;

//*********************************************************
// save Bitmap32 to PNG image file
// input:   srcBitmap         source bitmap
//          transparent       =true: transparent pixels
//          bgColor32         background color 32 bit
//          compressionLevel  compression level, range 0..9, default = 9
//          interlaceMethod   interlaced method, use imNone or imAdam7
// return:  boolean           =true: bitmap saved as PNG image file
//---------------------------------------------------------
function SaveBitmap32ToPNG (sourceBitmap: TBitmap32;
                             transparent: Boolean;
                             bgColor32: TColor32;
                             filename: String;
                             compressionLevel: TCompressionLevel = 9;
                             interlaceMethod: TInterlaceMethod = imNone): boolean;
var  png: tPNGObject;
begin
   result := false;
   try
     png := Bitmap32ToPNG (sourceBitmap, false, transparent, WinColor(bgColor32),
                           compressionLevel, interlaceMethod);
     try
       png.SaveToFile (filename);
     finally
       png.Free;
       result := true;
     end;
   except
   end;
end;
//---------------------------------------------------------
(*
function SaveBitmap32ToPNG (sourceBitmap: TBitmap32;
                             transparent: Boolean;
                             bgColor32: TColor32;
                             filename: String;
                             compressionLevel: TCompressionLevel = 9;
                             interlaceMethod: TInterlaceMethod =
imNone): boolean;
var  png: tPNGObject;
      FileStream: TFileStream;
begin
   result := false;
   try
     FileStream := TFileStream.Create(filename, fmCreate);
     try
       png := Bitmap32ToPNG (sourceBitmap, false, transparent,
WinColor(bgColor32),
                             compressionLevel, interlaceMethod);
       try
         png.SaveToStream (FileStream);
       finally
         png.Free;
         result := true;
       end;
     finally
       FileStream.Free;
     end;
   except
   end;
end;
*)
(*
//*********************************************************
// code example of loading and saving a PNG image file
//---------------------------------------------------------
procedure PNGExample;
var  transparent: boolean;
      myBitmap: tBitmap32;
begin
   myBitmap := TBitmap32.Create;
   transparent := true;
   if LoadPNGintoBitmap32 (MyBitmap, 'example1.png', transparent)
   then begin
     if transparent then
       // add anything else that should be done if we a transparent PNG
image...
       MyBitmap.DrawMode := dmBlend
     else
       MyBitmap.DrawMode := dmOpaque;

     SaveBitmap32ToPNG (myBitmap, transparent, clBlack, 'savetest.png', 5);
   end;
   myBitmap.Free;
end;

begin
   // PNGExample;      // delete comment to test loading and saving PNG
image
*)
end.
